require 'zdc.doc'
require 'zsvc.que'
require 'zsvc.packet'
require 'zsvc.accept'
require 'zsvc.evhandle'

module(..., package.seeall)

local Client= {}
zsvc.evhandle.InitEvent(Client)
local Client_mt = {__metatable = {}, __index = Client}

function MakeInhMT(ch)
	ch=ch or {}
	for _i,_j in pairs(Client) do
		ch[_i]=_j
	end
	return ch
end

function new(params,childmt)
	local obj = setmetatable({logger=params.logger,react=params.react,fd=params.fd,apps=params.apps,clis=params.clis,que=zsvc.que.new(),sp=zsvc.packet.new(),rp=zsvc.packet.new()}, childmt or Client_mt)	
	obj.authed=false
	obj.accid=''
	obj.authtag='Anonymous' .. tostring(obj)
	local a,b=obj.fd:getpeername()
	obj.name='?@'..tostring(a)..':'..tostring(b)
	obj:_bv_init()
	return obj
end

function Client:OnClose(fd)
	self.clis:DelOne(self.accid,self)
	self.clis:DelTmpOne(self.authtag,self)
	self.logger:debug('Client close fd for ' .. ((self.fd and self.fd:getpeername()) or ''))
	if self.fd then
		self:_bv_close()
		self.fd:close()
		self.fd=nil
	end
end

function Client:EndMsg(appid,ch,msg)
	if type(appid)=='table' then
		self:SendPacket(appid)
		self:TrySend()
		return
	end
	local np=zsvc.packet.new()
	np:SetMsg(appid,ch,{err=tostring(msg)})
	self:SendPacket(np)
	self:TrySend()
end
function Client:OnMsg(packet)
	local h=packet:ParseHeader()
	local pos,ch=packet:GetCH()
	ch.path=ch.path or {}
	ch.accid=self.accid
	if not self.authed then
		local por,body=packet:GetMsg()
		local r,msg=self:OnCheckAuthMsg(body)
		if not r then
			self:EndMsg(h.appid,ch,msg)
			error(msg)
		end
		ch.authtag=self.authtag
		self.clis:AddTmpOne(self.authtag,self)
		table.insert(ch.path,self.authtag)
	else
		if ch.logout then
			error(self.name .. " logout")
		end
		table.insert(ch.path,self.accid)
	end
	local app=self.apps:FindApp(h.appid,self)
	if app then
		local np=zsvc.packet.new()
		np:SetMsg2(h.appid,ch,packet.buf,pos)
		app:SendPacket(np)
		return
	else
		if not self.authed then
			self:EndMsg(h.appid,ch,"Client can't auth user")
			error("Client can't auth user")
		end
	end
		
	local np=zsvc.packet.new()
	np:SetMsg(h.appid,ch,{err="can't find app"})
	self:SendPacket(np)
	return
end

function Client:OnCheckAuthMsg(msg)
	return false
end
function Client:OnAuthed(packet)
	if self.authed then return nil,'re authed' end
	local por,msg=packet:GetMsg()
	print(logging.tostring(msg))
	--local accid=msg.ch.accid
	local accid=msg.bd.ret[1]
	if accid then
		self.accid=accid
		self.name=accid..string.sub(self.name,2)
		self.authed=true
		self.clis:DelTmpOne(self.authtag,self)
		return self.clis:AddOne(self.accid,self,msg.ch,msg.bd)
	end
	return nil,'invalid accid, can not auth'
end
